import requests
from parsel import Selector
import re
import time
import logging
import sys
from api.apps.sdk.ImageRecognizer import ImageRecognizer  # 导入图片识别器
from api.db.services.rice_service import RiceService  # 导入数据库操作类
from flask import request, jsonify
from threading import Thread
import threading
from flask_login import login_required


# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# 定义基础URL
BASE_URL = "https://www.ricedata.cn"
# 主程序延迟配置
MAIN_PROGRAM_DELAY = 1  # 单位：秒

stop_flag = False  # 全局停止标志

# 全局线程列表
active_tasks = []

# 初始化图片识别器和数据库
recognizer = ImageRecognizer(download_delay=1)

def signal_handler(sig, frame):
    """处理 Ctrl+C 信号"""
    global stop_flag
    print("\n正在终止程序...")
    stop_flag = True
    sys.exit(0)

def convert_img_src(img_src):
    """将相对路径的img src转换为绝对路径"""
    if img_src.startswith("../../"):
        return f"{BASE_URL}/" + img_src[6:]
    return img_src

def clean_text(text, replace_img = False):
    """清理文本，将img标签替换为识别出的数字"""
    if not text:
        return ""

    if replace_img:
        # 查找所有img标签并替换为识别出的数字
        def replace_img(match):
            img_src = match.group(1)
            absolute_src = convert_img_src(img_src)
            logging.info(f"缓存存在此数字：{absolute_src} 结果为: {absolute_src}")

            # 识别图片中的数字（内部会使用缓存）
            recognized_number, from_cache = recognizer.recognize_image(absolute_src)

            # 根据缓存状态输出不同日志
            if from_cache:
                logging.info(f"缓存存在此数字：{absolute_src} 结果为: {recognized_number}")
            else:
                logging.info(f"识别成功：{absolute_src} 结果为: {recognized_number}")

            return recognized_number

        # 使用正则表达式替换img标签为识别结果
        text = re.sub(r'<img src="(.*?)">', replace_img, text)

    text = re.sub(r'<a\b[^>]*>(.*?)</a>', r'\1', text)
    text = re.sub(r'</p>', '', text)
    text = text.replace('&nbsp;', ' ').replace('\n', ' ').strip()
    text = re.sub(r'\s+', ' ', text)
    text = re.sub(r'<[^>]+>', '', text)

    replacements = {
        '&nbsp;': ' ',
        '&amp;': '&',
        '&lt;': '<',
        '&gt;': '>',
        '&quot;': '"',
        '&apos;': "'"
    }

    for entity, char in replacements.items():
        text = text.replace(entity, char)

    text = ' '.join(text.split())  # 合并所有空白字符
    return text.strip()


def parse_parents(parent_source):
    """从亲本来源中分离父本和母本"""
    father = mother = ""
    
    if not parent_source:
        return father, mother
    
    # 处理带♀♂符号的格式（如："济A(♀) 香妃占2号(♂)"）
    if "(♀)" in parent_source and "(♂)" in parent_source:
        parts = parent_source.split()
        for part in parts:
            if "(♀)" in part:
                mother = part.replace("(♀)", "").strip()
            elif "(♂)" in part:
                father = part.replace("(♂)", "").strip()
        return father, mother
    
    # 处理其他常见格式（如："A/B"、"A×B"等）
    separators = ['×', '/', '//', '×号', '×']
    for sep in separators:
        if sep in parent_source:
            parts = [p.strip() for p in parent_source.split(sep, 1)]
            if len(parts) == 2:
                father, mother = parts[1], parts[0]  # 通常第一个是母本，第二个是父本
                break
    
    return father, mother


def extract_seed_info(html_content):
    """提取种子基本信息"""
    selector = Selector(text=html_content)
    
    seed_info = {
        "亲本来源": "",
        "选育单位": "",
        "品种类型": "",
        "适种地区": "",
        "完成人":"",
    }

    # 提取基本信息表格（只取第一个table的实体）
    info_table = selector.xpath('(//table[@class="data-table"][.//span[contains(., "爬虫")]])[1]')[0]

    logging.info(f"info_table: {info_table.get()}")
    if info_table:
        info_text = info_table.xpath('.//td[@style="font-size:14px"]').get()
        logging.info(f"info_text: {info_text}")
        for i, info_key in enumerate(seed_info.keys()):
            # 提取亲本来源
            parent_match = re.search(fr'{info_key}[:：](.*?)(?=<br>|$)', info_text)
            logging.info(f"parent_match: {parent_match}")
            if parent_match:
                seed_info[info_key] = clean_text(parent_match.group(1))
            else:
                seed_info[info_key] = ""

            logging.info(f"{info_key}: {seed_info[info_key]}")

        # 取得所有<p>的实体列表
        other_infos = info_table.xpath('string(//p)').getall()
        seed_info["其他"] = ""
        for other_info in other_infos:
            logging.info(f"other_info: {other_info}")
            seed_info["其他"] = seed_info["其他"] + "。" + clean_text(other_info)
        logging.info(f"其他: {seed_info['其他']}")

        # 取得整个table的字符串
        info_table = selector.xpath('string(//table[@class="data-table"][.//span[contains(., "爬虫")]])').get()
        logging.info(f"info_table：{info_table}")
        seed_info["全信息"] = clean_text(info_table)
        logging.info(f"全信息：{seed_info['全信息']}")

        # 提取品种名称
        name = selector.xpath('//table[@class="data-table"]//th[contains(., "・")]/text()').get()
        name = clean_text(name.replace('・', '')) if name else ""
        seed_info["种名"] = name
        logging.info(f"name: {name}")

    return seed_info


def extract_approval_data(html_content):
    """从HTML内容中提取审定信息（保留img标签但转换src为绝对路径）"""
    selector = Selector(text=html_content)
    approval_datas = []

    logging.info(f"html_content: {html_content}")
    
    # 找到所有审定表格
    approval_tables = selector.xpath('//table[@class="data-table"][.//th[contains(., "审定")]]')
    
    for table in approval_tables:
        logging.info(f"table: {table.get()}")

        approval_data = {
            "申请者": "",
            "育种者": "",
            "品种来源": "",
            "特征特性": "",
            "产量表现": "",
            "栽培技术要点": "",
            "栽培要点": "",
            "审定意见": "",
            "其他": "",
        }

        approval_infos = table.xpath('.//p')
        for i, approval_info in enumerate(approval_infos):
            logging.info(f"approval_info: {approval_info.get()}")
            clean_info = clean_text(approval_info.get(), True)
            for j, approval_key in enumerate(approval_data.keys()):
                if approval_key == "其他":
                    approval_data["其他"] = approval_data["其他"] + "。" + clean_info
                    logging.info(f"其他: {approval_data['其他']}")
                    break
                field_data = re.search(fr'{approval_key}[:：](.*?)(?=<br>|$)', clean_info)
                logging.info(f"field_data: {field_data}")
                if field_data:
                    approval_data[approval_key] = field_data.group(1)
                    logging.info(f"{approval_key}: {approval_data[approval_key]}")
                    break

        # 审定编号
        approval_num = clean_text(table.xpath('.//th[1]//text()').get() or "")
        approval_data["审定编号"] = approval_num
        logging.info(f"审定编号: {approval_num}")

        # 取得整个table的字符串
        approval_data["全信息"] = clean_text(table.get(), True)
        logging.info(f"全信息：{approval_data['全信息']}")

        approval_datas.append(approval_data)

    return approval_datas

def get_rice_detail_data(url):
    """获取水稻详情页面的数据"""
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
    }
    
    try:
        recognizer.clear_cache()  # 处理新页面时清空缓存


        response = requests.get(url, headers=headers)
        response.encoding = response.apparent_encoding
        html_content = response.text
        
        # 提取种子信息
        seed_info = extract_seed_info(html_content)

        # 提取审定信息
        approval_data = extract_approval_data(html_content)
        
        return seed_info, approval_data
        
    except Exception as e:
        logging.info(f"获取数据失败: {e}")
        return {}, []

class RiceCrawlerTask(Thread):
    def __init__(self, start_id, end_id):
        super().__init__()
        self.start_id = start_id
        self.end_id = end_id
        self.current_id = start_id
        self.stop_flag = threading.Event()  # 改为 Event 对象
        self.total = abs(end_id - start_id) + 1  # 确保总数正确
        self.lock = threading.Lock()  # 添加线程锁

    def stop(self):
        """安全停止任务"""
        self.stop_flag.set()
        logging.info(f"任务停止信号已发送 (ID范围: {self.start_id}-{self.end_id})")

    def should_stop(self):
        """检查是否应该停止"""
        return self.stop_flag.is_set()

    def run(self):
        try:
            logging.info(f"爬虫任务开始: {self.start_id} -> {self.end_id}")
            BASE_URL = "https://www.ricedata.cn"
            for variety_id in range(self.start_id, self.end_id + 1):
                logging.info(f"进入循环，当前ID: {variety_id}")  # 确认进入循环
                # 检查停止信号
                if self.should_stop():
                    logging.info("任务被用户终止")
                    return
                    
                self.current_id = variety_id
                logging.info(f"正在处理ID: {variety_id}")
                # 判断当前ID是否存在
                if RiceService._if_variety_id_exists(variety_id):
                    logging.info(f"ID {variety_id} 已存在，跳过")
                    continue
    
                try:
                    url = f"{BASE_URL}/variety/varis/{variety_id}.htm"
                    logging.info(f"访问URL: {url}")
                    seed_info, approval_data = get_rice_detail_data(url)

                    logging.info(f"获得种子原始信息: {seed_info}")
                    logging.info(f"获得种子审定信息: {approval_data}")
                    
                    if seed_info["种名"]:
                        father, mother = parse_parents(seed_info["亲本来源"])
                        seed_info.update({
                            "father_parent": father,
                            "mother_parent": mother
                        })
                        
                        if not RiceService.save_variety_data(seed_info, approval_data, variety_id):
                            logging.error(f"保存品种ID {variety_id} 数据失败")
                        else:
                            logging.info(f"成功保存品种ID: {variety_id}")
                    else:
                        logging.warning(f"无效品种ID: {variety_id}")
                        
                except Exception as e:
                    logging.error(f"处理品种ID {variety_id} 失败: {e}")
                    time.sleep(5)

                time.sleep(5)  # 请求间隔
            
            logging.info("爬虫任务完成")
            sys.exit(0)
        except Exception as e:
            logging.error(f"爬虫任务异常终止: {e}")

    def stop(self):
        self.stop_flag = True


@manager.route('/rice_run_get', methods=['POST'])
@login_required
def rice_run_get():
    global active_tasks

    data = request.json
    start_id = data.get('start_id')
    end_id = data.get('end_id')

    if not start_id or not end_id:
        return jsonify({"status": "error", "message": "请输入有效的起始和结束ID"}), 400
    
    # 停止所有现有任务
    for task in active_tasks:
        if task.is_alive():
            task.stop()
    
    # 创建并启动新任务
    new_task = RiceCrawlerTask(start_id, end_id)
    active_tasks.append(new_task)
    new_task.start()
    
    return jsonify({
        "status": "started",
        "message": f"已启动爬虫任务，从{start_id}到{end_id}",
        "start_id": start_id,
        "end_id": end_id,
        "code": 0
    })

@manager.route('/rice_stop', methods=['POST'])
@login_required
def rice_stop():
    """停止当前所有任务"""
    global active_tasks
    
    try:
        # 获取当前活动任务数
        running_tasks = [t for t in active_tasks if t.is_alive()]
        
        if not running_tasks:
            return jsonify({
                "status": "idle",
                "message": "没有正在运行的任务",
                "code": 0
            })
        
        # 停止所有任务
        stopped_count = 0
        for task in running_tasks:
            try:
                task.stop()  # 调用每个任务的停止方法
                stopped_count += 1
            except Exception as e:
                logging.error(f"停止任务失败: {e}")
        
        # 清理任务列表
        active_tasks = [t for t in active_tasks if not t.is_alive()]
        
        return jsonify({
            "status": "stopped",
            "message": f"已停止{stopped_count}个运行中的任务",
            "code": 0,
            "stopped_count": stopped_count
        })
        
    except Exception as e:
        logging.error(f"停止任务操作异常: {e}")
        return jsonify({
            "code": 500,
            "message": f"停止任务时发生错误: {str(e)}"
        }), 500

@manager.route('/rice_status', methods=['GET'])
@login_required
def rice_status():
    try:
        # 清理已完成任务
        global active_tasks
        
        active_tasks = [t for t in active_tasks if t.is_alive()]
        
        if active_tasks:
            task = active_tasks[-1]  # 获取最近的任务
            processed = task.start_id - task.current_id
            progress = min(100, int((processed / task.total) * 100)) if task.total > 0 else 0
            
            return jsonify({
                "status": "running",
                "message": "任务正在运行中",
                "code": 0,
                "progress": progress,
                "current_id": task.current_id,
                "start_id": task.start_id,
                "end_id": task.end_id
            })
            
        return jsonify({
            "status": "idle",
            "message": "没有正在运行的任务",
            "code": 0
        })
    except Exception as e:
        logging.error(f"获取任务状态失败: {e}")
        return jsonify({"code": 100, "message": str(e)}), 500
    
def check_thread_alive():
    """检查线程是否存活"""
    global active_tasks
    if active_tasks:
        return active_tasks.is_alive()
    return False


@manager.route('/varieties_list', methods=['POST'])
@login_required
def list_rice_varieties():
    """获取水稻品种列表接口"""
    try:
        data = request.json
        params = {
            'page': data.get('page', 1),
            'per_page': data.get('per_page', 20),
            'seed_id': data.get('seed_id'),
            'name': data.get('name'),
            'drought_resistant': data.get('drought_resistant', False),
            'glutinous': data.get('glutinous', False),
            'form_type': data.get('form_type', '不限定'),
            'rice_type': data.get('rice_type', '不限定')
        }
        
        result = RiceService.get_varieties_list(params)
        return jsonify({
            'code': 0,
            'data': result
        })
    except Exception as e:
        logging.error(f"查询水稻品种列表失败: {e}")
        return jsonify({
            'code': 500,
            'message': f'查询失败: {str(e)}'
        }), 500

@manager.route('/varieties_detail', methods=['GET'])
@login_required
def get_rice_variety_detail():
    """获取水稻品种详情接口(GET)"""
    try:
        variety_id = request.args.get('variety_id')
        
        if not variety_id:
            return jsonify({
                'code': 400,
                'message': '缺少品种ID参数'
            }), 400
        
        variety_data = RiceService.get_variety_detail(variety_id)
        if not variety_data:
            return jsonify({
                'code': 404,
                'message': '未找到该品种'
            }), 404
        
        return jsonify({
            'code': 0,
            'data': variety_data
        })
    except Exception as e:
        logging.error(f"查询水稻品种详情失败: {e}")
        return jsonify({
            'code': 500,
            'message': f'查询失败: {str(e)}'
        }), 500

@manager.route('/varieties_test', methods=['GET'])
@login_required
def get_rice_variety_test():
    """用来测试数据库里面有没有东西的测试接口"""
    try:
        varieties = RiceService.dataTest()
        return jsonify({
            'code': 0,
            'data': varieties 
        }),200
    except Exception as e:
        logging.error(f"查询水稻品种详情失败: {e}")
        return jsonify({
            'code': 500,
           'message': f'查询失败: {str(e)}'
        }), 500